#ifndef __MY_SERVICE__
#define __MY__SERVICE__
#include "data.hpp"
#include "httplib.h"
#include <memory>

std::unique_ptr<cloud::DataManager> data(new cloud::DataManager());

namespace cloud
{
    class Service
    {
    private:
        std::string _server_ip;
        int _server_port;
        std::string _download_prefix;
        httplib::Server _server;

    private:
        static void Upload(const httplib::Request &req, httplib::Response &rsp)
        {
            // post /upload  文件数据在正文中（正文并不全是文件数据）
            // 判断有没有上传的文件区域
            auto ret = req.has_file("file");
            if (ret == false)
            {
                rsp.status = 400;
                return;
            }
            // 获取文件数据内容
            const auto &file = req.get_file_value("file");
            ////file.filename//文件名称    file.content//文件数据
            std::string back_dir = Config::GetInstance()->GetBackDir();
            std::string realpath = back_dir + FileUtil(file.filename).FileName();
            FileUtil fu1(back_dir);
            fu1.CreateDirectory();
            FileUtil fu(realpath);
            // 将数据写入文件
            fu.SetContent(file.content);
            // 组织备份文件信息
            BackupInfo info;
            info.NewBackupInfo(realpath);
            // 将组织好的文件信息添加到数据管理
            data->Insert(info);
            return;
        }
        static std::string TimetoStr(time_t t)
        {
            std::string tmp = std::ctime(&t);
            return tmp;
        }
        static void LsitShow(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1.获取所有文件的备份信息
            std::vector<BackupInfo> arry;
            data->GetAll(&arry);
            // 2.将备份信息组成成html文件格式
            std::stringstream ss;
            ss << "<html><head><title>Download</title><meta charset=\"UTF-8\"></head>"; // 标题
            ss << "<body><h1>Download</h1><table>";
            for (auto &a : arry)
            {
                ss << "<tr>"; // 每一行
                std::string filename = FileUtil(a.real_path).FileName();
                ss << "<td><a href='" << a.url << "'>" << filename << "</a></td>"; // 每一列
                ss << "<td align='right'>" << TimetoStr(a.mtime) << "</td>";
                ss << "<td align='right'>" << a.fsize / 1024 << "k</td>";
                ss << "</tr>";
            }
            ss << "</table></body></html>";
            rsp.body = ss.str();                         // 响应正文
            rsp.set_header("Content-Type", "text/html"); // 响应头部信息，告知返回的内容类型
            rsp.status = 200;                            // 响应状态码
            return;
        }
        static std::string GetETag(const BackupInfo &info)
        {
            // etg :  filename-fsize-mtime
            FileUtil fu(info.real_path);
            std::string etag = fu.FileName();
            etag += '-';
            etag += std::to_string(info.fsize);
            etag += "-";
            etag += std::to_string(info.mtime);
            return etag;
        }
        static void Download(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1.获取客户端请求的资源路径path
            // 2.根据资源路径，获取文件的备份信息
            BackupInfo info;
            data->GetOneByURL(req.path, &info);
            // 3.判断文件是否被压缩
            if (info.pack_flag)
            {
                FileUtil fu(info.pack_path);
                std::cout<<info.real_path<<std::endl;
                fu.UnCompress(info.real_path); // 将文件解压到备份目录下
                // 4.删除压缩文件
                fu.Remove();
                info.pack_flag == false;
                // 5.更新备份信息
                data->Update(info);
            }

            // 热点续传功能
            bool retrans = false;
            std::string old_etag;
            if (req.has_header("If-Range"))
            {
                std::string old_etag = req.get_header_value("If-Range");
                // 有If-Range字段且，这个字段的值与请求文件的最新etag一致则符合断点续传
                if (old_etag == GetETag(info))
                {
                    retrans = true;
                }
            }
            // 4. 读取文件数据，放入rsp.body中
            FileUtil fu(info.real_path);
            if (retrans == false)
            {
                fu.GetContent(&rsp.body);
                // 5.设置头部字段
                rsp.set_header("Accept-Ranges", "bytes");                   // 支持断点续传
                rsp.set_header("ETag", GetETag(info));                      // 表示资源唯一性
                rsp.set_header("Content-Type", "application/octet-stream"); // 响应的内容类型
                rsp.status = 200;                                           // 响应状态码
            }
            else
            {
                // httplib内部实现了对于区间请求也就是断点续传请求的处理
                // 只需要我们用户将文件所有数据读取到rsp.body中，它内部会自动根据请求
                // 区间，从body中取出指定区间数据进行响应
                //  std::string  range = req.get_header_val("Range"); bytes=start-end
                fu.GetContent(&rsp.body);
                rsp.set_header("Accept-Ranges", "bytes");  // 支持断点续传
                rsp.set_header("ETag", GetETag(info));    // 表示资源唯一性
                rsp.set_header("Content-Type", "application/octet-stream");    // 响应的内容类型
                // rsp.set_header("Content-Range", "bytes start-end/fsize");   //内部实现了，表示区间请求的开始位置，长度，总大小
                rsp.status = 206; // 区间请求响应状态码的是206
            }
            return;
        }

    public:
        Service()
        {
            Config *config = Config::GetInstance();
            _server_ip = config->GetServerIp();
            _server_port = config->GetServerPort();
            _download_prefix = config->GetDownloadPrefix();
        }
        bool RunModule()
        {
            // 上传文件
            _server.Post("/upload", Upload);
            // 查看上传列表
            _server.Get("/listshow", LsitShow);
            _server.Get("/", LsitShow);
            std::string download_url = _download_prefix + "(.*)";
            _server.Get(download_url, Download);
            _server.listen(_server_ip.c_str(), _server_port);
            return true;
        }
    };
}

#endif